﻿using KinonekoSoftware.Studio.Compatibility;
// ReSharper disable MemberCanBeMadeStatic.Global

namespace KinonekoSoftware.Studio.Pages.Shenanigans
{
    public abstract class TalkingGalleryViewModel : RepositoryGalleryItem
    {
        private readonly TalkingEngine       _Engine_Talking;
        private readonly InstanceCacheEngine _Engine_Cache;
        private readonly HashSet<string>     _CharacterIDHashSet;
        private readonly TalkingChannelType  _type;

        private int         _version_cache;
        private int         _version_talking;
        private Character   _selectedCharacter;
        private TalkingBase _selectedChannel;

        protected TalkingGalleryViewModel(TalkingChannelType type)
        {
            Platform.GetEngine<TalkingEngine, InstanceCacheEngine>(out var runtime,
                                                                   out _Engine_Talking,
                                                                   out _Engine_Cache);
            _type               = type;
            _CharacterIDHashSet = new HashSet<string>();
            Channels            = new ObservableCollection<TalkingBase>();


            AddCharacterCommand    = CreateCommand(DoAddCharacterCommand);
            RemoveCharacterCommand = CreateCommand<Character>(DoRemoveCharacterCommand);

            AddTalkingChannelCommand    = CreateCommand(DoAddTalkingChannelCommand);
            OpenTalkingChannelCommand   = CreateCommand<TalkingBase>(DoOpenTalkingChannelCommand);
            RemoveTalkingChannelCommand = CreateCommand<TalkingBase>(DoRemoveTalkingChannelCommand);
        }


        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------

        private async void Initialize()
        {
            using (var session = await Ioc.Get<IBusyServiceEX>().BeginSession("正在加载数据..."))
            {
                
                //
                // 兼容性监测
                // 详情请参阅方法自带注释。
                await ShenanigansCompatible.IsCompatible(session);
                
                //
                // 初始化
                CharacterDataSource.Initialize();
                
                //
                //
                await session.Await();
            }

            _version_cache   = _Engine_Cache.Version;
            _version_talking = _Engine_Talking.Version;
        }

        private void AddOrCache(Character character, bool loading = true)
        {
            if (character is null)
            {
                return;
            }


            if (_CharacterIDHashSet.Add(character.Id))
            {
                if (!loading)
                {
                    //
                    //
                    _Engine_Talking.AddCharacter(character);
                }

                //
                //
                _CharacterIDHashSet.Add(character.Id);
                Characters.Add(character);
            }
        }



        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------
        protected override void OnStart()
        {
            Initialize();
            base.OnStart();
        }

        protected override void OnResume()
        {
            if (_version_cache   != _Engine_Cache.Version ||
                _version_talking != _Engine_Talking.Version)
            {
                Initialize();
            }

            base.OnResume();
        }




        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------
        protected abstract string GetNewChannelDescription();
        protected abstract TalkingBase OnCreateInstance(string name, Character owner);



        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------
        private async void DoAddCharacterCommand()
        {
            var r = await InstancePickerViewModel.Multiple(InstanceType.Character, _CharacterIDHashSet);

            if (!r.IsFinished)
            {
                return;
            }

            //
            //
            foreach (var character in r.Value.Select(x => new Character
                {
                    Id     = x.Id,
                    Name   = x.Name,
                    Avatar = x.Avatar,
                }))
            {
                //
                //
                CharacterDataSource.AddOrCache(character, false);
            }
        }

        private async void DoRemoveCharacterCommand(Character character)
        {
            if (character is null)
            {
                return;
            }

            if (!await RemoveItem())
            {
                return;
            }

            CharacterDataSource.Remove(character);
        }

        private async void DoAddTalkingChannelCommand()
        {
            if (SelectedCharacter is null)
            {
                return;
            }


            var r = await SingleText(TitleSR.New, GetNewChannelDescription());

            if (!r.IsFinished)
            {
                return;
            }

            var character = SelectedCharacter;
            var talking   = OnCreateInstance(r.Value, character);


            //
            //
            _Engine_Talking.AddChannel(talking);
            _Engine_Talking.AddMember(character, talking);

            //
            //
            Channels.Add(talking);
        }

        private void DoOpenTalkingChannelCommand(TalkingBase talking)
        {

            if (talking is null)
            {
                return;
            }


            var context = new PageContext
            {
                Id = talking.Id,
            };

            if (talking is ChannelTalking channelTalking)
            {

                //
                //
                context.Set<ChannelTalking>(ContextBase.Key_Value, channelTalking);

                //
                //
                GoTo<ChannelTalkingViewModel>(context);
            }
            else
            {

                //
                //
                context.Set<FriendTalking>(ContextBase.Key_Value, (FriendTalking)talking);

                //
                //
                GoTo<FriendTalkingViewModel>(context);
            }
        }

        private async void DoRemoveTalkingChannelCommand(TalkingBase talking)
        {

            if (talking is null)
            {
                return;
            }

            if (!await RemoveItem())
            {
                return;
            }
            
            //
            //
            talking.Remove(_Engine_Talking);

            //
            //
            _Engine_Talking.RemoveChannel(talking);
            _Engine_Talking.RemoveMemberByChannel(talking);
            
            //
            //
            Channels.Remove(talking);
        }





        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------


        
        public TalkingBase SelectedChannel
        {
            get => _selectedChannel;
            set
            {
                SetValue(ref _selectedChannel, value);
                PushToView();
            }
        }

        public Character SelectedCharacter
        {
            get => _selectedCharacter;
            set
            {
                SetValue(ref _selectedCharacter, value);

                //
                //
                if (_selectedCharacter is null)
                {
                    return;
                }

                //
                //
                Channels.AddMany(_Engine_Talking.GetChannels(_selectedCharacter.Id, _type), true);
                PushToView();
            }
        }

        public ObservableCollection<Character>   Characters => CharacterDataSource.GlobalScopedCollection;
        public ObservableCollection<TalkingBase> Channels   { get; }

        public ICommandEX AddCharacterCommand    { get; }
        public ICommandEX RemoveCharacterCommand { get; }

        public ICommandEX AddTalkingChannelCommand    { get; }
        public ICommandEX OpenTalkingChannelCommand   { get; }
        public ICommandEX RemoveTalkingChannelCommand { get; }
    }
}